package com.tencent.wepay.service.pay;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tencent.wepay.WepayManager;
import com.tencent.wepay.constant.enums.TradeTypeEnum;
import com.tencent.wepay.handler.xml.XStreamHandler;
import com.tencent.wepay.listener.Listener;
import com.tencent.wepay.protocol.http.HttpRequest;
import com.tencent.wepay.protocol.pay.domain.BaseOrder;
import com.tencent.wepay.protocol.pay.request.CloseOrderRequest;
import com.tencent.wepay.protocol.pay.request.OrderInfoRequest;
import com.tencent.wepay.protocol.pay.request.OrderRequest;
import com.tencent.wepay.protocol.pay.request.PrepayRequest;
import com.tencent.wepay.protocol.pay.response.CloseOrderResponse;
import com.tencent.wepay.protocol.pay.response.OrderInfoResponse;
import com.tencent.wepay.protocol.pay.response.OrderResponse;
import com.tencent.wepay.spi.WepayRepository;

public class OrderService {
	private final static String payUrl="https://api.mch.weixin.qq.com/pay/unifiedorder";
	private final static String getPayInfoUrl="https://api.mch.weixin.qq.com/pay/orderquery";
	private final static String closeUrl="https://api.mch.weixin.qq.com/pay/closeorder";
	private static Logger logger=LoggerFactory.getLogger(OrderService.class);
	public static OrderResponse order(BaseOrder order){
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(order.getTradeType())){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(order.getTradeType())){
			repository=WepayManager.getAppRepository();
		}
		OrderRequest request=new OrderRequest();
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		try {
			BeanUtils.copyProperties(request, order);		
			if(request.validation()){
				String result=HttpRequest.getInstance().post(payUrl,request.toXML());
				OrderResponse response=XStreamHandler.toBean(OrderResponse.class,result);
				if ("SUCCESS".equalsIgnoreCase(response.getReturnCode())&&"SUCCESS".equalsIgnoreCase(response.getResultCode())) {
					PrepayRequest prepayRequest=new PrepayRequest.Builder(request.getTradeType()).appid(request.getAppid())
						.mchId(request.getMchId()).prepayid(response.getPrepayId()).key(request.getKey()).build();
					response.setPrepayRequest(prepayRequest);
				}
				return response;
			}
		} catch (Exception e) {
				logger.error("send request error", e);
		}		
		return null;
	}
	public static OrderResponse order(BaseOrder order,Listener<OrderRequest,OrderResponse> listener){
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(order.getTradeType())){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(order.getTradeType())){
			repository=WepayManager.getAppRepository();
		}
		OrderRequest request=new OrderRequest();
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		try {
			if(listener!=null)
				listener.beforeSend(request);
			BeanUtils.copyProperties(request, order);		
			if(request.validation()){
				String result=HttpRequest.getInstance().post(payUrl,request.toXML());
				OrderResponse response=XStreamHandler.toBean(OrderResponse.class,result);
				if ("SUCCESS".equalsIgnoreCase(response.getReturnCode())&&"SUCCESS".equalsIgnoreCase(response.getResultCode())) {
					PrepayRequest prepayRequest=new PrepayRequest.Builder(request.getTradeType()).appid(request.getAppid())
							.mchId(request.getMchId()).prepayid(response.getPrepayId()).key(request.getKey()).build();
					response.setPrepayRequest(prepayRequest);
					if(listener!=null)
						listener.onSuccess(response);
				}
				else{
					if(listener!=null)
						listener.onFail(response);
				}
				return response;
			}
		} catch (Exception e) {
			listener.onError(e);
			logger.error("send request error", e);
		}
		return null;
	}
	public static OrderInfoResponse queryByTradeNo(String tradeNo,TradeTypeEnum tradeType){
		OrderInfoRequest request=new OrderInfoRequest();
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(tradeType)){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(tradeType)){
			repository=WepayManager.getAppRepository();
		}	
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		request.setTradeNo(tradeNo);
		if(request.validation()){
			try {
				String result= HttpRequest.getInstance().post(getPayInfoUrl,request.toXML());
				return XStreamHandler.toBean(OrderInfoResponse.class, result);
			} catch (Exception e) {
				logger.error("send request error", e);
			}
		}		
		return null;
	}
	public static OrderInfoResponse queryByTransId(String tradeId,TradeTypeEnum tradeType){
		OrderInfoRequest request=new OrderInfoRequest();
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(tradeType)){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(tradeType)){
			repository=WepayManager.getAppRepository();
		}	
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		request.setTransactionId(tradeId);
		if(request.validation()){
			try {
				String result= HttpRequest.getInstance().post(getPayInfoUrl,request.toXML());
				return XStreamHandler.toBean(OrderInfoResponse.class, result);
			} catch (Exception e) {
				logger.error("send request error", e);
			}
		}		
		return null;
	}
	public static CloseOrderResponse close(String tradeNo,TradeTypeEnum tradeType){
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(tradeType)){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(tradeType)){
			repository=WepayManager.getAppRepository();
		}
		CloseOrderRequest request=new CloseOrderRequest();
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		request.setTradeNo(tradeNo);
		try {
			if(request.validation()){
				String result=HttpRequest.getInstance().post(closeUrl,request.toXML());
				CloseOrderResponse response=XStreamHandler.toBean(CloseOrderResponse.class,result);
				return response;
			}
		} catch (Exception e) {
				logger.error("send request error", e);
		}		
		return null;
	}
	public static CloseOrderResponse close(String tradeNo,TradeTypeEnum tradeType,Listener<CloseOrderRequest,CloseOrderResponse> listener){
		WepayRepository repository=null;
		if(TradeTypeEnum.JSAPI.equals(tradeType)){
			repository=WepayManager.getJsapiRepository();
		}
		else if(TradeTypeEnum.APP.equals(tradeType)){
			repository=WepayManager.getAppRepository();
		}
		CloseOrderRequest request=new CloseOrderRequest();
		request.setAppid(repository.getAppid());
		request.setKey(repository.getKey());
		request.setMchId(repository.getMchId());
		request.setTradeNo(tradeNo);
		try {
			if(listener!=null)
				listener.beforeSend(request);
			if(request.validation()){
				String result=HttpRequest.getInstance().post(closeUrl,request.toXML());
				CloseOrderResponse response=XStreamHandler.toBean(CloseOrderResponse.class,result);
				if ("SUCCESS".equalsIgnoreCase(response.getReturnCode())) {
					if(listener!=null)
						listener.onSuccess(response);
				}
				else{
					if(listener!=null)
						listener.onFail(response);
				}
				return response;
			}
		} catch (Exception e) {
			listener.onError(e);
			logger.error("send request error", e);
		}
		return null;
	}
}
